package web.controller.sys;

import framework.exceptions.BusinessException;
import framework.runtime.SystemContext;
import framework.utils.JsonUtil;
import framework.vo.L;
import framework.vo.R;
import framework.vo.ResultInfo;
import framework.vo.ResultList;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import system.entity.SysTaskJob;
import system.service.sys.SysTaskJobService;
import system.task.Task;
import system.task.TaskManager;
import system.task.config.TaskConfig;
import system.task.defined.TaskStatus;
import system.task.errors.TaskException;
import system.task.logger.buffer.TaskLogBufferAdmin;
import system.task.logger.buffer.TaskLogBufferItem;
import system.task.utils.TaskUtil;
import system.task.vo.SysTaskRunning;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/sys/task/job")
@Api(tags = "任务计划")
public class SysTaskJobController {
    @Autowired
    private SysTaskJobService sysTaskJobService;
    @Autowired
    private TaskManager taskManager;
    @Autowired
    private TaskConfig taskConfig;

    @ApiOperation("添加任务计划")
    @PostMapping("/add")
    public ResultInfo<Long> add(@ModelAttribute SysTaskJob param) throws TaskException {
        this.validSchedule(param);
        //
        java.util.Date now = new java.util.Date();
        param.setCreateTime(now);
        Integer added = sysTaskJobService.add(param);
        // 导入新添加的任务
        SysTaskJob job = sysTaskJobService.loadById(param.getId());
        Task task = new Task();
        BeanUtils.copyProperties(job, task);
        taskManager.addTask(task);
        //
        ResultInfo<Long> info = new ResultInfo<>(param.getId());
        return info;
    }

    @ApiOperation("删除任务计划")
    @PostMapping("/del")
    public ResultInfo<Integer> del(@RequestParam("ids") List<Long> ids) throws TaskException {
        int rows = 0;
        List<SysTaskJob> sysTaskJobs = sysTaskJobService.loadByIds(ids);
        for (SysTaskJob sysTaskJob : sysTaskJobs) {
            //删除任务
            taskManager.delTask(sysTaskJob.getName());
            //删除记录
            rows += sysTaskJobService.deleteById(sysTaskJob.getId());
        }
        ResultInfo<Integer> info = new ResultInfo<>(rows);
        return info;
    }

    @ApiOperation("更新任务计划")
    @PostMapping("/edit")
    public ResultInfo<Integer> edit(@ModelAttribute SysTaskJob param) throws TaskException {
        this.validSchedule(param);
        //
        SysTaskJob sysTaskJob = sysTaskJobService.loadById(param.getId());
        if (sysTaskJob == null) {
            return R.ok(0);
        }
        //
        Task oldTask = taskManager.getTask(sysTaskJob.getName());
        Integer updated = sysTaskJobService.update(param);
        if (updated > 0) {
            // 删除旧任务
            if (oldTask != null) {
                taskManager.delTask(oldTask.getName());
            }
            // 添加新任务
            SysTaskJob job = sysTaskJobService.loadById(param.getId());
            Task task = new Task();
            BeanUtils.copyProperties(job, task);
            taskManager.addTask(task);
        }
        //
        ResultInfo<Integer> info = new ResultInfo<>(updated);
        return info;
    }

    @ApiOperation("查看任务计划")
    @GetMapping("/info")
    public ResultInfo<SysTaskRunning> info(@RequestParam("id") Long id) throws TaskException {
        SysTaskRunning running = sysTaskJobService.loadInfo(id);
        return new ResultInfo<>(running);
    }

    @ApiOperation("任务计划列表")
    @GetMapping("/list")
    public ResultList<SysTaskRunning> list(SysTaskJob param, @RequestParam(value = "pageIndex", defaultValue = "1") Integer pageIndex, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) throws TaskException {
        return sysTaskJobService.loadRunning(param, pageIndex, pageSize);
    }

    @ApiOperation("任务时间列表")
    @GetMapping("/times")
    public ResultList<Date> times(@RequestParam String name,
                                  @RequestParam(required = false) Integer size,
                                  @RequestParam(required = false) Date afterTime) throws TaskException {
        if (size == null) size = 100;
        if (afterTime == null) afterTime = new Date();
        List<Date> dates = sysTaskJobService.loadTriggerTimes(name, size, afterTime);
        return L.ok(dates);
    }

    @ApiOperation("运行任务")
    @PostMapping("/run")
    public ResultInfo<Integer> run(@RequestParam("name") String name, @RequestParam("param") String param) throws TaskException {

        SysTaskJob query = new SysTaskJob();
        query.setName(name);
        SysTaskJob info = sysTaskJobService.first(query);
        if (info == null) {
            String msg = SystemContext.getMessageDefault("task.not.found", "Not found task " + name);
            return R.failed(msg);
        }

        Task task = taskManager.getTask(name);
        if (task == null) {
            String msg = SystemContext.getMessageDefault("task.no.run.scheduler", "Task not run on this scheduler {0}", TaskUtil.hostname());
            return R.failed(msg);
        }

        if (TaskStatus.DISABLED.equals(info.getStatus())) {
            String msg = SystemContext.getMessageDefault("task.no.run.disabled", "not allowed run because task has disabled");
            return R.failed(msg);
        }

        Map<String, Object> map = new HashMap<>();
        //自定义参数构建
        if (StringUtils.hasText(param)) {
            HashMap hashMap = JsonUtil.parse(param, HashMap.class);
            for (Object o : hashMap.keySet()) {
                map.put(String.valueOf(o), hashMap.get(o));
            }
        }

        //
        try {
            taskManager.startTask(name, map);
        } catch (TaskException e) {
            String msg = SystemContext.getMessageDefault("error.operate.failed", "operation failed {0}", e.getMessage());
            return R.failed(msg);
        }

        return new ResultInfo<>(1);
    }

    @ApiOperation("停止任务")
    @PostMapping("/stop")
    public ResultInfo<Integer> stop(@RequestParam("name") String name) throws TaskException {

        SysTaskJob query = new SysTaskJob();
        query.setName(name);
        SysTaskJob info = sysTaskJobService.first(query);
        if (info == null) {
            String msg = SystemContext.getMessageDefault("task.not.found", "Not found task " + name);
            return new ResultInfo<>().failed(msg);
        }

        Task task = taskManager.getTask(name);
        if (task == null) {
            String msg = SystemContext.getMessageDefault("task.no.run.scheduler", "Task not run on this scheduler {0}", TaskUtil.hostname());
            return new ResultInfo<>().failed(msg);
        }

        try {
            taskManager.stopTask(name);
        } catch (TaskException e) {
            String msg = SystemContext.getMessageDefault("error.operate.failed", "operation failed {0}", e.getMessage());
            return new ResultInfo<>().failed(msg);
        }

        return new ResultInfo<>(1);
    }

    @ApiOperation("任务执行日志")
    @GetMapping("/log")
    public ResultList<TaskLogBufferItem> log(@RequestParam String name, @RequestParam Integer lastIndex) {
        if (lastIndex < 1)
            lastIndex = 0;
        List<TaskLogBufferItem> list = TaskLogBufferAdmin.instance.list(name, lastIndex);
        return L.ok(list);
    }

    private void validSchedule(SysTaskJob param) {
        if (!StringUtils.hasText(param.getSchedule())) {
            return;
        }
        Task task = new Task();
        BeanUtils.copyProperties(param, task);
        Trigger trigger;
        try {
            trigger = TaskUtil.parseTrigger(task, new TriggerKey("test", "test"));
        } catch (Exception exception) {
            trigger = null;
        }
        if (trigger == null) {
            String msg = SystemContext.getMessageDefault("sys.request.parameter.invalid", "Request parameter {0} invalid", task.getSchedule());
            throw new BusinessException(msg);
        }
    }
}